package com.greenhou.sqlSession.defaults;

import com.greenhou.executor.Executor;
import com.greenhou.executor.SimpleExecutor;
import com.greenhou.pojo.Configuration;
import com.greenhou.pojo.MappedStatement;
import com.greenhou.sqlSession.SqlSession;

import java.lang.reflect.*;
import java.util.List;

public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        MappedStatement mappedStatement=this.configuration.getMappedStatementMap().get(statementId);
        Executor executor=new SimpleExecutor();
        return executor.query(configuration,mappedStatement,params);
    }

    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<T> list=this.selectList(statementId,params);
        if(list!=null){
            if(list.size()==1){
                return list.get(0);
            }else if(list.size()>1){
                throw new RuntimeException("query result is more then one,but expected one");
            }
        }
        return null;
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        //使用JDK动态代理为Dao接口生成代理对象个并返回
        Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //底层不管怎么实现，都是调用jdbc接口去实现数据查询
                //处理方法名
                String methodName=method.getName();
                String className=method.getDeclaringClass().getName();
                String statementId=className+"."+methodName;
                //处理参数
                //根据返回参数类型判断需要调用哪个方法
                Type genericReturnType = method.getGenericReturnType();
                //判断返回类型是否进行了泛型类型参数化（List<User>类似）
                if(genericReturnType instanceof ParameterizedType){
                    return selectList(statementId,args);
                }else{
                    return selectOne(statementId,args);
                }
            }
        });
        return (T) obj;
    }
}
